
package com.joysuch.wwyt.core.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.zlg.common.enums.BusinessTypeEnum;
import com.joysuch.wwyt.api.basedata.service.BaseImageSyncService;
import com.joysuch.wwyt.bp.repository.BpContractorStaffDao;
import com.joysuch.wwyt.core.bean.BaseAttachmentBean;
import com.joysuch.wwyt.core.bean.BaseImageTypeRepositoryBean;
import com.joysuch.wwyt.core.entity.BaseImageRepository;
import com.joysuch.wwyt.core.entity.BaseImageTypeRepository;
import com.joysuch.wwyt.core.enums.DeleteFlag;
import com.joysuch.wwyt.core.enums.ImageTypes;
import com.joysuch.wwyt.core.repository.BaseImageRespositoryDao;
import com.joysuch.wwyt.core.repository.BaseImageTypeRepositoryDao;
import com.joysuch.wwyt.core.repository.BaseUserDao;
import com.joysuch.wwyt.core.service.BaseConfigService;
import com.joysuch.wwyt.core.service.BaseImageRepositoryService;
import com.joysuch.wwyt.core.support.Context;
import com.joysuch.wwyt.log.service.FileUploadLogService;
import com.joysuch.wwyt.util.Md5Util;
import com.joysuch.wwyt.util.RotateImageUtil;
import com.joysuch.wwyt.util.SnowFlakeUtil;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service()
@Transactional
@Slf4j
public class BaseImageRepositoryServiceImpl implements BaseImageRepositoryService {

    @Value("${wwyt.base.serverUrl}")
    private String serverUrl;

    @Value("${wwyt.image.upload.dir}")
    private String imageUploadDir;

    @Value("${wwyt.image.upload.aiAlarm.dir}")
    private String aiAlarmImg;

    @Value("${wwyt.image.thumbnail.suffix}")
    private String imageThumbnailSuffix;

    @Value("${wwyt.image.thumbnail.width}")
    private Integer thumbnailWidth = 200;

    @Value("${wwyt.image.thumbnail.height}")
    private Integer thumbnailHeight = 300;

    @Autowired
    private BaseImageRespositoryDao imageRepositoryDao;
    @Autowired
    private BaseImageTypeRepositoryDao baseImageTypeRepositoryDao;
    @Autowired
    private BaseConfigService baseConfigService;
    @Autowired
    private BaseImageSyncService baseImageSyncService;
    @Autowired
    private FileUploadLogService fileUploadLogService;
    @Autowired
    private BaseUserDao baseUserDao;
    @Autowired
    private BpContractorStaffDao bpContractorStaffDao;

    @Override
    public Long saveAIImage(byte[] bytes , Long tenentId , String orgCode) throws IOException {
        String fileName = UUID.randomUUID().toString().replace("-", "");
        String extension = "jpg";
        // 避免将文件存储在一个目录下，使用日期
        String subdir = DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN);
        //自定义AI报警目录加时间
        String dir = aiAlarmImg + File.separator + subdir ;
        String relativePath = subdir + "/" + fileName + "." + extension;
        File newFile = new File(dir + File.separator + fileName + "." + extension);
        File thumbFile = new File(dir + File.separator + fileName + "_" + imageThumbnailSuffix + "." + extension);
        // 处理数据
        for (int i = 0; i < bytes.length; ++i) {
            if (bytes[i] < 0) {
                bytes[i] += 256;
            }
        }
        FileUtils.forceMkdir(new File(dir));
        OutputStream out = new FileOutputStream(dir + File.separator + fileName + "." + extension);
        out.write(bytes);
        out.flush();
        out.close();
        // 压缩文件，按照宽度一定的格式压缩文件
        BaseImageRepository image = generateThumbnail(thumbnailWidth, thumbnailHeight, subdir, relativePath, newFile,
                thumbFile, fileName, false, null, fileName + "." + extension,tenentId,orgCode);
        return image.getId();
    }

    @Override
    public Long saveImage(File file) throws IOException {
        String fingerPrint = generateFingerPrint(file);
        BaseImageRepository exist = imageRepositoryDao.findFirstByFingerPrint(fingerPrint);
        if (exist != null) {
            return exist.getId();
        }

        String fileName = fingerPrint;// UUID.randomUUID().toString().replace("-", "");
        String extension = FilenameUtils.getExtension(file.getName());
        // 避免将文件存储在一个目录下，使用文件名前2个字符作为子文件夹
        String subdir = DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN);
        String dir = imageUploadDir + File.separator + subdir;
        String relativePath = subdir + "/" + fileName + "." + extension;
        File newFile = new File(dir + File.separator + fileName + "." + extension);
        File thumbFile = new File(dir + File.separator + fileName + "_" + imageThumbnailSuffix + "." + extension);

        FileUtils.forceMkdir(new File(dir));
        FileUtils.copyFile(file, newFile);

        // 压缩文件，按照宽度一定的格式压缩文件
        BaseImageRepository image = generateThumbnail(thumbnailWidth, thumbnailHeight, subdir, relativePath, newFile,
                thumbFile, fingerPrint, false, null, file.getName(),null,null);
        return image.getId();
    }

    @Override
    public BaseImageRepository getSaveImage(File file) throws IOException {
        String fingerPrint = generateFingerPrint(file);
        BaseImageRepository exist = imageRepositoryDao.findFirstByFingerPrint(fingerPrint);
        if (exist != null) {
            return exist;
        }

        String fileName = fingerPrint;// UUID.randomUUID().toString().replace("-", "");
        String extension = FilenameUtils.getExtension(file.getName());
        // 避免将文件存储在一个目录下，使用文件名前2个字符作为子文件夹
        String subdir = DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN);
        String dir = imageUploadDir + File.separator + subdir;
        String relativePath = subdir + "/" + fileName + "." + extension;
        File newFile = new File(dir + File.separator + fileName + "." + extension);
        File thumbFile = new File(dir + File.separator + fileName + "_" + imageThumbnailSuffix + "." + extension);

        FileUtils.forceMkdir(new File(dir));
        FileUtils.copyFile(file, newFile);

        // 压缩文件，按照宽度一定的格式压缩文件
        BaseImageRepository image = generateThumbnail(thumbnailWidth, thumbnailHeight, subdir, relativePath, newFile,
                thumbFile, fingerPrint, false, null, file.getName(),null,null);
        return image;
    }

    @Override
    public Long saveImage(MultipartFile cover1, String imageUploadDir, String thumbnailSuffix, Integer thumbnailWidth,
                          Integer thumbnailHeight, boolean syncFlag) throws IOException, Exception {
        String fingerPrint = generateFingerPrint(cover1);
        BaseImageRepository exist = imageRepositoryDao.findFirstByFingerPrint(fingerPrint);
        if (exist != null) {
            //兼容旧数据
            if ( baseConfigService.checkIfSync() && syncFlag) {
                if (exist.getUniqueId() == null) {
                    exist.setUniqueId(SnowFlakeUtil.getImageId());
                    exist.setLocateSync(false);
                }
                boolean b = baseImageSyncService.syncPeopleCap(cover1, exist.getOriginPath(), exist.getUniqueId());
                exist.setLocateSync(b);
                imageRepositoryDao.save(exist);
            }
            // 判断服务器上是否有图片
            String path = imageUploadDir + "/" + exist.getOriginPath();
            File imagFile = new File(path);
            log.info("图片上传信息：{}", path + imagFile.exists());
            if (imagFile.exists()) {
                return exist.getId();
            }
        }
        String fileName = fingerPrint;// UUID.randomUUID().toString().replace("-", "");
        String extension = FilenameUtils.getExtension(cover1.getOriginalFilename());
        // 避免将文件存储在一个目录下，使用文件名前2个字符作为子文件夹
        String subdir = DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN);
        String dir = imageUploadDir + File.separator + subdir;
        String relativePath = subdir + "/" + fileName + "." + extension;
        File newFile = new File(dir + File.separator + fileName + "." + extension);
        File thumbFile = new File(dir + File.separator + fileName + "_" + thumbnailSuffix + "." + extension);

        FileUtils.forceMkdir(new File(dir));
        cover1.transferTo(newFile);
        // 生成压缩文件
        BaseImageRepository image = generateThumbnail(thumbnailWidth, thumbnailHeight, subdir, relativePath, newFile,
                thumbFile, fingerPrint, syncFlag, cover1, cover1.getOriginalFilename(),null,null);
        return image.getId();
    }

    @Override
    public Long saveRotateImage(MultipartFile cover1, String imageUploadDir, String thumbnailSuffix, Integer thumbnailWidth,
                          Integer thumbnailHeight, boolean syncFlag) throws IOException, Exception {
        String fingerPrint = generateFingerPrint(cover1);

        String fileName = fingerPrint;// UUID.randomUUID().toString().replace("-", "");
        String extension = FilenameUtils.getExtension(cover1.getOriginalFilename());
        // 避免将文件存储在一个目录下，使用文件名前2个字符作为子文件夹
        String subdir = DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN);
        String dir = imageUploadDir + File.separator + subdir;
        String relativePath = subdir + "/" + fileName + "." + extension;
//        File newFile = new File(dir + File.separator + fileName + "." + extension);
        File thumbFile = new File(dir + File.separator + fileName + "_" + thumbnailSuffix + "." + extension);

        FileUtils.forceMkdir(new File(dir));

        BufferedImage sourceImg = ImageIO.read(cover1.getInputStream());
        BufferedImage rotate = RotateImageUtil.rotateImage(sourceImg, -90);
        ImageIO.write(rotate, "png", new File(imageUploadDir+ File.separator , fileName + "." + extension));
        File  newFile= new File(imageUploadDir+ File.separator, fileName + "." + extension);

//
//        cover1.transferTo(newFile);
        // 生成压缩文件
        BaseImageRepository image = generateThumbnail(thumbnailWidth, thumbnailHeight, subdir, relativePath, newFile,
                thumbFile, fingerPrint, syncFlag, cover1, cover1.getOriginalFilename(),null,null);
        return image.getId();
    }

    /**
     * @param thumbnailWidth
     * @param thumbnailHeight
     * @param subdir
     * @param relativePath
     * @param newFile
     * @param thumbFile
     * @param fingerPrint
     * @return
     * @throws IOException
     */
    protected BaseImageRepository generateThumbnail(Integer thumbnailWidth, Integer thumbnailHeight, String subdir,
                                                    String relativePath, File newFile, File thumbFile, String fingerPrint, boolean syncFlag, MultipartFile cover1, String name
                                                    , Long tenentId , String orgCode) throws IOException {
        // 压缩文件，按照宽度一定的格式压缩文件
        // compressFile()
        String pathName = newFile.getAbsolutePath();
        BaseImageRepository image = new BaseImageRepository();
        try {
            BufferedImage bImage = ImageIO.read(newFile);
            if (null != tenentId && !StringUtils.isEmpty(orgCode)){
                image.setTenentId(tenentId);
                image.setOrgCode(orgCode);
            }
            image.setDeleteFlag(DeleteFlag.EFFECTIVE.getCode());
            image.setOriginPath(relativePath);
            image.setOriginLength(bImage.getHeight());
            image.setOriginWidth(bImage.getWidth());
            // 缩略图文件信息
            Thumbnails.of(bImage).size(thumbnailWidth, thumbnailHeight).toFile(thumbFile);

            image.setFingerPrint(fingerPrint);
            BufferedImage thumbImage = ImageIO.read(thumbFile);
            image.setThumbnailPath(subdir + "/" + thumbFile.getName());
            image.setThumbnailLength(thumbImage.getHeight());
            image.setThumbnailWidth(thumbImage.getWidth());
            image.setUploadTime(new Date());
            image.setUniqueId(SnowFlakeUtil.getImageId());
            image.setLocateSync(false);
            if (baseConfigService.checkIfSync() && syncFlag && cover1 != null) {
                boolean b = baseImageSyncService.syncPeopleCap(cover1, relativePath, image.getUniqueId());
                image.setLocateSync(b);
            }
            imageRepositoryDao.save(image);
            fileUploadLogService.savaLog(BusinessTypeEnum.IMAGE.getBusinessCode(), BusinessTypeEnum.IMAGE.getBusinessName(), name, 1, "图片上传成功");
        } catch (IOException e) {
            log.error("生成缩略图问题出错： " + e.getMessage(), e);
            log.info("-----尝试cmyk转化----- pathName=" + pathName);
            fileUploadLogService.savaLog(BusinessTypeEnum.IMAGE.getBusinessCode(), BusinessTypeEnum.IMAGE.getBusinessName(), name, 0, "图片生成缩略图问题出错: msg: " + e.getMessage() + " exception: " + e);
            try {
                BufferedImage img = ImageIO.read(newFile);
                ImageOutputStream output = ImageIO.createImageOutputStream(newFile);
                String extension = FilenameUtils.getExtension(newFile.getName()).toLowerCase();
                if (!ImageIO.write(img, extension, output)) {
                    log.info("-----cmyk转化异常:{}-----");
                }
                Thumbnails.of(img).scale(0.4f).toFile(pathName);
                log.info("-----cmyk转化成功-----");
                fileUploadLogService.savaLog(BusinessTypeEnum.IMAGE.getBusinessCode(), BusinessTypeEnum.IMAGE.getBusinessName(), name, 1, "图片cmyk转化成功");
            } catch (IOException e1) {
                log.info("-----cmyk转化异常:{}-----" + e1.getMessage(), e1);
                fileUploadLogService.savaLog(BusinessTypeEnum.IMAGE.getBusinessCode(), BusinessTypeEnum.IMAGE.getBusinessName(), name, 0, "图片cmyk转化异常: msg: " + e1.getMessage() + " exception: " + e1);
            }

        }
        return image;
    }

    private String generateFingerPrint(MultipartFile cover1) throws IOException {
        return Md5Util.getMd5ByFile(cover1.getInputStream());
    }

    private String generateFingerPrint(File cover1) throws IOException {
        return Md5Util.getMd5ByFile(cover1);
    }

    @Override
    public BaseImageRepository findById(Long id) {
        return imageRepositoryDao.getOne(id);
    }


    @Override
    public String generateImageUrlById(Long id) {
        return serverUrl + "/image/view?id=" + id;
    }

    @Override
    public String generateThumbnailImageUrlById(Long id) {
        return serverUrl + "/image/view?id=" + id + "&type=" + ImageTypes.THUMBNATIL.getCode();
    }

    @Override
    public BaseAttachmentBean findBeanById(Long id) {
        // BaseImageRepository repo = findById(id);
        BaseAttachmentBean bean = new BaseAttachmentBean();
        BaseImageRepository repository = this.findById(id);
        if (repository != null) {
            bean.setDownloadUrl(generateImageUrlById(id));
            bean.setId(id);
//            bean.setTypeCode(repository.getTypeCode());
        }
        // bean.setName(FilenameUtils.getName(repo.getOriginPath()));
        return bean;
    }

    /**
     * 保存图片库
     *
     * @param typeBean
     * @return
     */
    @Override
    public BaseImageTypeRepository saveImageTypeRepository(BaseImageTypeRepositoryBean typeBean) {
        BaseImageTypeRepository type = new BaseImageTypeRepository();
//        List<BaseImageTypeRepository> types = baseImageTypeRepositoryDao.findByImageIdAndTypeCode(imageId, typeCode);
        if (typeBean.getTypeId() != null) {
            Optional<BaseImageTypeRepository> otr = baseImageTypeRepositoryDao.findById(typeBean.getTypeId());
            if (otr.isPresent()) {
                type = otr.get();
            }
        }
        BeanUtils.copyProperties(typeBean, type);
        return baseImageTypeRepositoryDao.save(type);
    }

    /**
     * 删除图片库图片
     *
     * @param typeIds
     */
    @Override
    public void deleteByTypeId(List<Long> typeIds) {
        if (!CollectionUtils.isEmpty(typeIds)) {
            for (Long typeId : typeIds) {
                BaseImageTypeRepository type = baseImageTypeRepositoryDao.findById(typeId).orElseThrow(() -> new IllegalArgumentException("该图片不存在"));
                if (type.getCanDelete() != null && type.getCanDelete().equals(0)) {
                    throw new IllegalArgumentException("该图片无法删除");
                }
                if ((type.getTypeCode().equals("user_cap") || type.getTypeCode().equals("staff_cap")) && baseConfigService.checkIfSync()) {
                    int u = baseUserDao.countByCapId(type.getImageId());
                    int s = bpContractorStaffDao.countByCapId(type.getImageId());
                    if (u + s > 0) {
                        throw new IllegalArgumentException("该图标已被人员/承包商人员使用,请勿删除");
                    }
                    boolean b = baseImageSyncService.SyncDeleteCaps(typeId);
                }
                baseImageTypeRepositoryDao.deleteById(typeId);

            }
        }

    }

    /**
     * 获取图片列表
     *
     * @param typeCodes 图片类型
     *                  environment_point  环境监测点
     *                  user_cap  人物帽子
     *                  staff_cap  承包商人员帽子
     *                  fast_screen_view  快捷大屏单图标
     * @return
     */
    @Override
    public List<BaseAttachmentBean> list(List<String> typeCodes) {
        List<BaseAttachmentBean> list = new ArrayList<>();
        List<BaseImageTypeRepository> types = baseImageTypeRepositoryDao.findByTypeCodes(typeCodes);
        if (!CollectionUtils.isEmpty(types)) {
            for (BaseImageTypeRepository type : types) {
                Optional<BaseImageRepository> obr = imageRepositoryDao.findById(type.getImageId());
                if (obr.isPresent()) {
                    BaseImageRepository repository = obr.get();
                    BaseAttachmentBean bean = this.findBeanById(repository.getId());
                    bean.setTypeId(type.getId());
                    bean.setCanDelete(type.getCanDelete());
                    bean.setTypeCode(type.getTypeCode());
                    list.add(bean);
                }
            }
        }
        return list;
    }

    @Override
    public BaseAttachmentBean findLogoImage() {
        BaseAttachmentBean bean = new BaseAttachmentBean();
        BaseImageTypeRepository logoType = baseImageTypeRepositoryDao.findLogoType(Context.getCurrentTenantId(), Context.getCurrentOrgCode());
        if (null != logoType){
            Optional<BaseImageRepository> logoImageOpt = imageRepositoryDao.findById(logoType.getImageId());
            if (logoImageOpt.isPresent()){
                BaseImageRepository baseImageRepository = logoImageOpt.get();
                bean.setDownloadUrl(generateImageUrlById(baseImageRepository.getId()));
                bean.setId(baseImageRepository.getId());
                bean.setTypeId(logoType.getId());
                bean.setCanDelete(logoType.getCanDelete());
                bean.setTypeCode(logoType.getTypeCode());
                return bean;
            }
        }
        return bean;
    }

    @Override
    public void uploadLogoImage(Long imageId) {
        BaseImageTypeRepository logoType = baseImageTypeRepositoryDao.findLogoType(Context.getCurrentTenantId(), Context.getCurrentOrgCode());
        //第一次新增没有logo图片类型
        if (null == logoType){
            BaseImageTypeRepository typeRepository = new BaseImageTypeRepository();
            typeRepository.setImageId(imageId);
            typeRepository.setTypeCode("logo");
            typeRepository.setCanDelete(0);
            baseImageTypeRepositoryDao.save(typeRepository);
        }else {
            logoType.setImageId(imageId);
            baseImageTypeRepositoryDao.save(logoType);
        }
    }

    @Override
    public String findAbsolutePathById(Long imageId) {
        BaseImageRepository rep = imageRepositoryDao.getOne(imageId);
        return imageUploadDir + File.separator + rep.getOriginPath();
    }

    @Override
    public Map<Long, String> findByIds(List<Long> imageIds) {
        Map<Long, String> map=new HashMap<>();
        List<BaseImageRepository> list = imageRepositoryDao.findByIds(imageIds);
        for (BaseImageRepository repository : list) {
            if (map.get(repository.getId())==null) {
                map.put(repository.getId(),imageUploadDir + File.separator + repository.getOriginPath());
            }
        }
        return map;
    }
}
